<?php

class yzCache extends yzCore{

	protected $aProperties = array(
		'yz.cache.default.method' 		=> 'file',
		'yz.cache.default.lifetime'		=> 3600,
		'yz.cache.default.timezone'		=> 'Europe/Paris',
		'yz.cache.default.dir'			=> '/tmp/',
		'yz.cache.default.extension'	=> '.yzc',
		'yz.cache.allowed.methods' 		=> 'memory,file', // db?
		'yz.cache.file.auto_search'		=> false,
		'yz.cache.file.onload_search'	=> true,
		'yz.cache.file.init_purge'		=> false,
		'yz.cache.file.end_purge'		=> true,
		'runtime.files_loaded'			=> false,
	); // function

	/**
	 * Initialize object
	 *
	 */
	public function init(){

		$this->setObject('yzRegistry');

		date_default_timezone_set($this->getProperty('yz.cache.default.timezone'));

		if (!file_exists($this->getProperty('yz.cache.default.dir'))){

			mkdir($this->getProperty('yz.cache.default.dir'));

		} // if

		if ($this->getProperty('yz.cache.file.onload_search')===true){

			$this->getCachedFiles();

		} // if

		if ($this->getProperty('yz.cache.file.init_purge')===true){

			$this->purge();

		} // if

	} // function


	/**
	 * Class' destructor
	 *
	 * Clears cache at exit, if yz.cache.file.end_purge set to true
	 *
	 */
	public function __destruct(){

		if ($this->getProperty('yz.cache.file.end_purge')===true){

			$this->purge();

		}	// if

		parent::__destruct();

	} // function __destruct()


	/**
	 * Clears cache from entries older than yz.cache.default.lifetime
	 *
	 * @param bool $bPurgeAll If set to true, clears all cache (default: false)
	 *
	 */
	public function purge($bPurgeAll = false){

		if ($this->getProperty('runtime.files_loaded')===false && $this->getProperty('yz.cache.file.auto_search')===true){

				$this->getCachedFiles();

		} // if

		foreach ($this->getObject('yzRegistry')->getNameSpace('_cache_log') as $sCacheId=>$aCacheData){

			if ($bPurgeAll || !$this->isActualCache($sCacheId)){

				switch ($aCacheData['method']){

					case 'memory':

						$this->getObject('yzRegistry')->unsetVar('_cache_data',$sCacheId);

					break;

					case 'file':

						unlink($this->getProperty('yz.cache.default.dir').$sCacheId.$this->getProperty('yz.cache.default.extension'));

					break;

				} // switch

				$this->getObject('yzRegistry')->unsetVar('_cache_log',$sCacheId);

			} // if

		} // foreach

	} // function

	/**
	 * Gets (nearly) unique cache id using md5 function
	 *
	 * @param string|null cache name, random number taken if ot given
	 *
	 */
	public function getCacheId($sString = null){

		if ($sString!=null && is_string($sString)){

			return md5($sString);

		} else {

			return md5(strval(mt_rand()));

		} // if

	} // function getCacheId()

	/**
	 * Checks whether given method is allowed
	 *
	 * @param string $sMethod Method of caching (implemented memory & file; only the second is persistent)
	 * @todo ipmlement db cache
	 *
	 */
	public function sanitizeMethod($sMethod = null){

		$sMethod = strval($sMethod);

		if ($sMethod == '' || !in_array($sMethod,explode(',',$this->getProperty('yz.cache.allowed.methods')))){

			$sMethod = $this->getProperty('yz.cache.default.method');

		} // if

		return $sMethod;

	} // function sanitizeMethod()

	/**
	 * Sets cache
	 *
	 * @param mixed $mData data
	 * @param string $sName name of cache, optional
	 * @param string $sMethod method of cache optional
	 *
	 * @return string cache id
	 */
	public function setCache(&$mData, $sName=null, $sMethod=null){

		$sMethod = $this->sanitizeMethod($sMethod);

		$sCacheId = $this->getCacheId($sName);

		switch ($sMethod){

			case 'memory':

				$this->getObject('yzRegistry')->setVar('_cache_data',$sCacheId,$mData);

			break;

			case 'file':

				file_put_contents($this->getProperty('yz.cache.default.dir').$sCacheId.$this->getProperty('yz.cache.default.extension'),serialize($mData));

			break;

		} // switch

		$this->getObject('yzRegistry')->setVar('_cache_log',$sCacheId,array('method'=>$sMethod,'timestamp'=>time()));

		return $sCacheId;

	} // function setCache()

	/**
	 * return cache with given cahe id
	 *
	 * @param string $sCacheId cache id
	 * @return mixed cache contents
	 */
	public function getCache($sCacheId){

		$aCacheData = $this->getObject('yzRegistry')->getVar('_cache_log',$sCacheId);

		if ($aCacheData && $this->isActualCache($sCacheId)){

			switch ($aCacheData['method']){

				case 'memory':

					return $this->getObject('yzRegistry')->getVar('_cache_data',$sCacheId);

				break;

				case 'file':

					$sFileName = $this->getProperty('yz.cache.default.dir').$sCacheId.$this->getProperty('yz.cache.default.extension');

					if (file_exists($sFileName)){

						return unserialize(file_get_contents($sFileName));

					} else {

						return null;

					} // if

				break;

			} // switch

		} else {

			if ($this->getProperty('runtime.files_loaded')===false && $this->getProperty('yz.cache.file.auto_search')===true){

				$this->getCachedFiles();

				return $this->getCache($sCacheId);

			} // if

		} // if

	} // function getCache

	/**
	 * Checks, wheter cache isn't out of date
	 */
	public function isActualCache($sCacheId){

		if (($aCacheData = $this->getObject('yzRegistry')->getVar('_cache_log',$sCacheId)) &&
		 (time()<$aCacheData['timestamp'] + $this->getProperty('yz.cache.default.lifetime'))){

			return true;

		} else {

			if ($this->getProperty('runtime.files_loaded')===false && $this->getProperty('yz.cache.file.auto_search')===true){

				$this->getCachedFiles();

				return $this->isActualCache();

			} // if

			return false;

		} // if

	} // function isActualCache

	/**
	 * gets all cached files from directory
	 */
	public function getCachedFiles(){

		$aFiles = glob($this->getProperty('yz.cache.default.dir').'*'.$this->getProperty('yz.cache.default.extension'));

		foreach ($aFiles as $sFile){$this->getObject('yzRegistry')->setVar('_cache_log',basename($sFile,$this->getProperty('yz.cache.default.extension')),array('method'=>'file','timestamp'=>filemtime($sFile)));

		} // foreach

		$this->setProperty('runtime.files_loaded',true);

		return count($aFiles);

	} // function getCachedFiles

} // class

?>